#include <windows.h>
#include "CResourceLibrary.h"
#include "CCommIOFunc.h"
#include <vector>
#include "CReleaseMacro.h"
#include "Shlwapi.h"
#include "D2d1helper.h"
#include <assert.h>
using namespace std;
CDXEffectLibrary::CDXEffectLibrary(CDXDevice* pDevice) : CDXBase(pDevice)
{

}
CDXEffectLibrary::~CDXEffectLibrary()
{
	
	for (std::map<wstring, CDXEffect*>::iterator iter = m_pEffectPathMap.begin(); iter !=  m_pEffectPathMap.end(); iter++)
	{
		SAFE_RELEASE(iter->second);
	}
	m_pEffectPathMap.clear();
	for (std::map<string, CDXEffect*>::iterator iter = m_pEffectNameMap.begin(); iter !=  m_pEffectNameMap.end(); iter++)
	{
		SAFE_RELEASE(iter->second);
	}
	m_pEffectNameMap.clear();

}
HRESULT CDXEffectLibrary::LoadEffectFromFile(const WCHAR* path, const char* name)
{
	if (path == NULL || name == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	wstring orgPath(path);

	vector<wstring> candPath(3);
	candPath.clear();
	string strName(name);
	GetCandidateAbsPath(candPath, orgPath);
	CDXEffect* pEffect = NULL;
	for (UINT p = 0; p < candPath.size(); p++)
	{	
		std::map<wstring, CDXEffect*>::iterator iter;
		iter = m_pEffectPathMap.find(candPath[p]);
		if (iter != m_pEffectPathMap.end())
		{
			pEffect = iter->second;
			break;
		}
	}
	if (pEffect == NULL)
	{
		wstring filePath = L"";
		for (UINT p =0; p < candPath.size(); p++)
		{
			if (PathFileExistsW(candPath[p].c_str()))
			{
				filePath = candPath[p];
				break;
			}
		}
		if (filePath.empty())
		{
			assert(0);
			return E_FAIL;
		}
		pEffect = new CDXEffect(m_pDevice);
		hr = pEffect->LoadFromFile(filePath.c_str());
		if (FAILED(hr))
		{
			assert(0);
			return hr;
		}
		m_pEffectPathMap[filePath] = pEffect;
	}

	std::map<string, CDXEffect*>::iterator nameIter; 
	nameIter = m_pEffectNameMap.find(strName);
	if (nameIter == m_pEffectNameMap.end())
	{
		m_pEffectNameMap[strName] = pEffect;
		SAFE_ADDREF(m_pEffectNameMap[strName]);
	}
	else
	{
		SAFE_RELEASE(m_pEffectNameMap[strName]);
		m_pEffectNameMap[strName] = pEffect;
		SAFE_ADDREF(m_pEffectNameMap[strName]);
	}
	return S_OK;
}
HRESULT CDXEffectLibrary::GetEffectByPath(const WCHAR* path, CDXEffect** ppEffect)
{
	wstring orgPath(path);
	vector<wstring> candPath;
	GetCandidateAbsPath(candPath, orgPath);
	for (UINT p = 0; p < candPath.size(); p++)
	{
		std::map<wstring, CDXEffect*>::iterator iter;
		iter = m_pEffectPathMap.find(candPath[p]);
		if (iter != m_pEffectPathMap.end())
		{
			*ppEffect = iter->second;
			return S_OK;
		}
	}
	
	return E_FAIL;
}
HRESULT CDXEffectLibrary::GetEffectByName(const char* name, CDXEffect** ppEffect)
{
	string strName(name);
	std::map<string, CDXEffect*>::iterator iter;
	iter = m_pEffectNameMap.find(strName);
	if (iter != m_pEffectNameMap.end())
	{
		*ppEffect = iter->second;
		return S_OK;
	}
	return E_FAIL;
}

CDXTextureLibrary::CDXTextureLibrary(CDXDevice* pDevice) :CDXBase(pDevice)
{

}
CDXTextureLibrary::~CDXTextureLibrary()
{
	for (std::map<wstring, CDXTexture2D*>::iterator iter = m_pTexturePathMap.begin(); iter != m_pTexturePathMap.end(); iter++)
	{
		SAFE_RELEASE(iter->second);
	}
	m_pTexturePathMap.clear();
}
HRESULT CDXTextureLibrary::LoadTextureFromFile(WCHAR* path)
{
	wstring orgPath(path);
	vector<wstring> candPath;
	GetCandidateAbsPath(candPath, orgPath);
	for (UINT p = 0; p < candPath.size(); p++)
	{	
		std::map<wstring, CDXTexture2D*>::iterator iter;
		iter = m_pTexturePathMap.find(candPath[p]);
		if (iter != m_pTexturePathMap.end())
		{
			return S_FALSE;
		}
	}
	wstring filePath = L"";
	for (UINT p =0; p < candPath.size(); p++)
	{
		if (PathFileExistsW(candPath[p].c_str()))
		{
			filePath = candPath[p];
		}
	}
	if (filePath.empty())
		return E_FAIL;
	HRESULT hr = S_OK;
	CDXTexture2D* pTexture = new CDXTexture2D(m_pDevice);

	hr = pTexture->LoadFromFile(filePath.c_str());
	if (FAILED(hr))
		return hr;
	m_pTexturePathMap[filePath] = pTexture;
	return S_OK;
}
HRESULT CDXTextureLibrary::GetTextureByPath(WCHAR* path, CDXTexture2D** ppTexture)
{
	wstring orgPath(path);
	vector<wstring> candPath;
	GetCandidateAbsPath(candPath, orgPath);
	for (UINT p = 0; p < candPath.size(); p++)
	{	
		std::map<wstring, CDXTexture2D*>::iterator iter;
		iter = m_pTexturePathMap.find(candPath[p]);
		if (iter != m_pTexturePathMap.end())
		{
			*ppTexture = iter->second;
			return S_OK;
		}
	}
	return E_FAIL;
}

bool operator < (const CD2DColorBrushLibrary::ColorBrushKey& key1, const CD2DColorBrushLibrary::ColorBrushKey& key2)
{
	return (memcmp((void*)&key1,(void*)&key2, sizeof(CD2DColorBrushLibrary::ColorBrushKey)) < 0);
}

CD2DColorBrushLibrary::CD2DColorBrushLibrary(CDXDevice* pDevice) : CDXBase(pDevice)
{

}
CD2DColorBrushLibrary::~CD2DColorBrushLibrary()
{
	for (std::map<ColorBrushKey, ID2D1SolidColorBrush*>::iterator iter = m_pColorBrushMap.begin(); iter != m_pColorBrushMap.end(); iter++)
	{
		SAFE_RELEASE(iter->second);
	}
	m_pColorBrushMap.clear();
}

HRESULT CD2DColorBrushLibrary::CreateSolidColorBrush(ID2D1RenderTarget* pD2DRT, const D2D1_COLOR_F& color)
{
	if (pD2DRT == NULL)
		return E_FAIL;
	std::map<CD2DColorBrushLibrary::ColorBrushKey, ID2D1SolidColorBrush*>::iterator iter;
	CD2DColorBrushLibrary::ColorBrushKey findKey = {pD2DRT, color};
	iter = m_pColorBrushMap.find(findKey);
	if (iter != m_pColorBrushMap.end())
	{
		return S_FALSE;
	}
	D2D1_BRUSH_PROPERTIES prop;
	prop.opacity = color.a;
	prop.transform = D2D1::IdentityMatrix();
	ID2D1SolidColorBrush* pBrush = NULL;
	HRESULT hr = S_OK;
	hr = pD2DRT->CreateSolidColorBrush(color, prop, &pBrush);
	if (FAILED(hr))
		return hr;
	m_pColorBrushMap[findKey] = pBrush;
	return S_OK;
}
HRESULT CD2DColorBrushLibrary::GetSolidColorBrush(ID2D1RenderTarget* pD2DRT, const D2D1_COLOR_F& color, ID2D1SolidColorBrush** ppBrush)
{
	if (pD2DRT == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	std::map<CD2DColorBrushLibrary::ColorBrushKey, ID2D1SolidColorBrush*>::iterator iter;
	CD2DColorBrushLibrary::ColorBrushKey findKey = {pD2DRT, color};
	iter = m_pColorBrushMap.find(findKey);
	if (iter == m_pColorBrushMap.end())
	{
		hr = CreateSolidColorBrush(pD2DRT, color );
		if (FAILED(hr))
			return hr;
	}
	*ppBrush = m_pColorBrushMap[findKey];
	return S_OK;
}

CDXMeshLibrary::CDXMeshLibrary(CDXDevice* pDevice) : CDXBase(pDevice)
{

}
CDXMeshLibrary::~CDXMeshLibrary()
{
	for (std::map<std::string, CDXMesh*>::iterator iter = m_pMeshNameMap.begin(); iter != m_pMeshNameMap.end(); iter++)
	{
		SAFE_RELEASE(iter->second);
	}
	m_pMeshNameMap.clear();

	for (std::map<std::wstring, CDXMesh*>::iterator iter = m_pMeshPathMap.begin(); iter != m_pMeshPathMap.end(); iter++)
	{
		SAFE_RELEASE(iter->second);
	}
	m_pMeshPathMap.clear();
}
HRESULT CDXMeshLibrary::LoadMeshFromFile(const WCHAR* path, const char* name)
{
	if (path == NULL || m_pDevice == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	wstring localPath(path);
	string strName(name);
	vector<wstring> candPath;
	GetCandidateAbsPath(candPath, localPath);
	wstring strfindPath = L"";
	for (UINT i =0; i < candPath.size(); i++)
	{
		std::map<std::wstring, CDXMesh*>::iterator iter;
		iter = m_pMeshPathMap.find(candPath[i]);
		if (iter != m_pMeshPathMap.end())
		{
			strfindPath = iter->first;
			break;
		}
	}
	if (strfindPath != L"")
	{
		if (name != NULL)
		{
			std::map<std::string, CDXMesh*>::iterator iter;
			iter = m_pMeshNameMap.find(strName);
			if (iter != m_pMeshNameMap.end())
			{
				SAFE_RELEASE(iter->second);
			}
			m_pMeshNameMap[strName] = m_pMeshPathMap[strfindPath];
			SAFE_ADDREF(m_pMeshNameMap[strName]);
		}
	}
	else
	{
		for (UINT i =0; i < candPath.size(); i++)
		{
			if (PathFindExtensionW(candPath[i].c_str()))
			{
				strfindPath = candPath[i];
				break;
			}
		}
		if (strfindPath != L"")
		{
			CDXMesh* pMesh = new CDXMesh(m_pDevice);
			hr = pMesh->LoadFromOBJFile(strfindPath.c_str());
			if (FAILED(hr))
			{
				SAFE_RELEASE(pMesh);
				return hr;
			}
			m_pMeshPathMap[strfindPath] = pMesh;
			if (name != NULL)
			{
				std::map<std::string, CDXMesh*>::iterator iter;
				iter = m_pMeshNameMap.find(strName);
				if (iter != m_pMeshNameMap.end())
				{
					SAFE_RELEASE(iter->second);
				}

				m_pMeshNameMap[strName] = m_pMeshPathMap[strfindPath];
				SAFE_ADDREF(pMesh);
			}
		}

	}
	return S_OK;
}
HRESULT CDXMeshLibrary::SetMesh(CDXMesh* pmesh, const char* name)
{
	if (pmesh == NULL || name == NULL)
		return E_FAIL;
	string strName(name);
	std::map<std::string, CDXMesh*>::iterator iter;
	iter = m_pMeshNameMap.find(strName);
	if (iter != m_pMeshNameMap.end())
	{
		SAFE_RELEASE(iter->second);
	}
	m_pMeshNameMap[strName] = pmesh;
	SAFE_ADDREF(pmesh);
	return S_OK;
}
HRESULT CDXMeshLibrary::GetMeshByPath(const WCHAR* path, CDXMesh** ppMesh)
{
	wstring localPath(path);
	vector<wstring> candPath;
	GetCandidateAbsPath(candPath, localPath);
	
	for (UINT i =0; i < candPath.size(); i++)
	{
		std::map<std::wstring, CDXMesh*>::iterator iter;
		iter = m_pMeshPathMap.find(candPath[i]);
		if (iter != m_pMeshPathMap.end())
		{
			*ppMesh = iter->second;
			return S_OK;
		}
	}
	return E_FAIL;
}
HRESULT CDXMeshLibrary::GetMeshByName(const char* name, CDXMesh** ppMesh)
{
	if (name == NULL)
		return E_FAIL;
	string strName(name);
	std::map<std::string, CDXMesh*>::iterator iter;
	iter = m_pMeshNameMap.find(strName);
	if (iter != m_pMeshNameMap.end())
	{
		*ppMesh = iter->second;
		return S_OK;
	}
	return E_FAIL;
}